package com.xjoyt.pay.master.services;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import com.xjoyt.pay.abstracts.AbstractService;
import com.xjoyt.pay.commons.ObjectUtils;
import com.xjoyt.pay.dto.ExecuteResult;
import com.xjoyt.pay.dto.PageParam;
import com.xjoyt.pay.dto.PageResult;
import com.xjoyt.pay.master.params.ChannelPageParam;
import com.xjoyt.pay.master.po.Channel;
import com.xjoyt.pay.master.po.Merchant;
import com.xjoyt.pay.master.po.MerchantCashRate;
import com.xjoyt.pay.master.po.MerchantChannel;
import com.xjoyt.pay.master.po.MerchantChannelCashRate;
import com.xjoyt.pay.master.po.MerchantChannelRate;
import com.xjoyt.pay.master.po.MerchantRate;
import com.xjoyt.pay.master.po.PayChannel;
import com.xjoyt.pay.master.repository.ChannelRepository;
import com.xjoyt.pay.master.repository.MerchantCashRateRepository;
import com.xjoyt.pay.master.repository.MerchantChannelCashRateRepository;
import com.xjoyt.pay.master.repository.MerchantChannelRateRepository;
import com.xjoyt.pay.master.repository.MerchantChannelRepository;
import com.xjoyt.pay.master.repository.MerchantRateRepository;
import com.xjoyt.pay.master.repository.MerchantRepository;
import com.xjoyt.pay.master.repository.PayChannelRepository;
import com.xjoyt.pay.master.vo.MerchantChannelMap;
import com.xjoyt.pay.master.vo.MerchantRateMap;
import com.xjoyt.pay.master.vo.RateEntry;

@Service
public class ChannelService extends AbstractService {

	@Autowired
	private ChannelRepository repository;

	@Autowired
	private PayChannelRepository payChannelRepository;

	@Autowired
	private MerchantRepository merchantRepository;

	@Autowired
	private MerchantRateRepository merchantRateRepository;

	@Autowired
	private MerchantCashRateRepository merchantCashRateRepository;

	@Autowired
	private MerchantChannelRepository merchantChannelRepository;

	@Autowired
	private MerchantChannelRateRepository merchantChannelRateRepository;

	@Autowired
	private MerchantChannelCashRateRepository merchantChannelCashRateRepository;

	@Autowired
	private RestTemplate restTemplate;

	public Channel get(String id) {
		return repository.findOne(id);
	}

	public ExecuteResult<Channel> save(Channel entity) {
		if (entity.addedDate == null)
			entity.addedDate = new Date();

		List<PayChannel> channels = null;
		if (StringUtils.isBlank(entity.id)) {
			channels = entity.channels;
			entity.addedDate = new Date();
			entity.channels = null;
			entity = repository.save(entity);
		} else {
			Channel po = repository.findOne(entity.id);
			if (po == null) {
				return ExecuteResult.fail("数据不存在");
			}
			channels = entity.channels;
			po.enabled = entity.enabled;
			po.name = entity.name;
			po.no = entity.no;
			po.registerUrl = entity.registerUrl;
			po.healthUrl = entity.healthUrl;
			po.healthEnabled = entity.healthEnabled;
			po.weight = entity.weight;
			po.payEnabled =entity.payEnabled;
			po.payLimit = entity.payLimit;
			po.payMinimum = entity.payMinimum;
			po.payUrl = entity.payUrl;
			po.payRate = entity.payRate;
			po.payMoney = entity.payMoney;
			po = repository.save(po);
			if (CollectionUtils.isNotEmpty(po.channels))
				for (PayChannel item : po.channels) {
					payChannelRepository.delete(item);
				}
			entity = po;
		}

		if (CollectionUtils.isNotEmpty(channels)) {
			for (PayChannel item : channels) {
				if (item.tradeType == null || item.payType == null) {
					continue;
				}
				item.id = 0;
				item.addedDate = new Date();
				item.channel = entity;
				payChannelRepository.save(item);
			}
		}

		return ExecuteResult.ok(entity);
	}

	public ExecuteResult<?> delete(String id) {
		repository.delete(id);
		return ExecuteResult.ok();
	}

	public PageResult<Channel> loadPage(PageParam<ChannelPageParam> param) {
		return repository.loadPage(param);
	}

	public ExecuteResult<?> setRegisterChannel(String id, String requestId) {
		Channel entity = repository.findOne(id);
		if (entity == null) {
			return ExecuteResult.fail("数据不存在");
		}

		if (StringUtils.isBlank(entity.registerUrl)) {
			return ExecuteResult.fail("进件接口URL未设置");
		}

		repository.save(entity);
		return ExecuteResult.ok();
	}

	public ExecuteResult<?> invokeRegisterChannel(List<String> ids) {
		ExecutorService threadPool = Executors.newCachedThreadPool();
		FutureTask<Object> future = new FutureTask<>(() -> {
			List<Channel> list = repository.findAllByIdIn(ids);
			for (Channel entity : list) {
				if (StringUtils.isBlank(entity.registerUrl) || entity.company == null) {
					continue;
				}
				register(entity);
			}
			return null;
		});
		threadPool.execute(future);
		return ExecuteResult.ok();
	}

	private void register(Channel entity) {
		List<Merchant> list = merchantRepository.findAllByCompanyIdIn(entity.company.id);
		for (Merchant item : list) {
			List<MerchantRate> rateList = merchantRateRepository.findAllByMerchantId(item.id);
			List<MerchantCashRate> cashRateList = merchantCashRateRepository.findAllByMerchantId(item.id);
			if (CollectionUtils.isEmpty(rateList) || CollectionUtils.isEmpty(cashRateList)) {
				continue;
			}

			MerchantRateMap param = new MerchantRateMap();
			ObjectUtils.fieldCopy(item, param);
			param.rateList = new ArrayList<>();
			List<RateEntry> rateEntryList = new ArrayList<>();
			rateList.forEach(i -> {
				RateEntry entry = new RateEntry();
				entry.type = i.type;
				entry.rate = i.rate;
				entry.limit = i.limit;
				entry.minimum = i.minimum;
				entry.money = i.money;
				rateEntryList.add(entry);
			});
			cashRateList.forEach(i -> {
				param.cashRate = i.rate;
				param.cashMoney = i.money;
				param.cashLimit = i.limit;
				param.cashMinimum = i.minimum;
			});
			try {
				MerchantChannelMap merchantChannel = restTemplate.postForObject(entity.registerUrl, param,
						MerchantChannelMap.class);
				if (merchantChannel == null || StringUtils.isBlank(merchantChannel.key)
						|| StringUtils.isBlank(merchantChannel.no)) {
					continue;
				}
				merchantChannelRepository.findAllByMerchantIdAndChannelId(item.id, entity.id)
						.forEach(i -> merchantChannelRepository.delete(i));
				MerchantChannel po = new MerchantChannel();
				ObjectUtils.fieldCopy(merchantChannel, po);
				po.rates = new ArrayList<>();
				po.channel = entity;
				po.addedDate = new Date();
				po.merchant = item;
				po.enabled = true;
				po = merchantChannelRepository.save(po);
				// if (CollectionUtils.isNotEmpty(merchantChannel.rateList))
				// for (RateEntry i : merchantChannel.rateList) {
				// if (i.rate <= 0 || i.type == null)
				// continue;
				// MerchantChannelRate r = new MerchantChannelRate();
				// r.merchantChannel = po;
				// r.rate = i.rate;
				// r.type = i.type;
				// merchantChannelRateRepository.save(r);
				// }
				if (CollectionUtils.isNotEmpty(rateEntryList))
					for (RateEntry i : rateEntryList) {
						if (i.rate <= 0 || i.type == null)
							continue;
						MerchantChannelRate r = new MerchantChannelRate();
						r.merchantChannel = po;
						r.rate = i.rate;
						r.type = i.type;
						r.limit = i.limit;
						r.minimum = i.minimum;
						r.money = i.money;
						merchantChannelRateRepository.save(r);
					}
				if (String.valueOf(param.cashLimit) != null || String.valueOf(param.cashMinimum) != null
						|| String.valueOf(param.cashMoney) != null || String.valueOf(param.cashRate) != null) {
					MerchantChannelCashRate rate = new MerchantChannelCashRate();
					rate.merchantChannel = po;
					rate.rate = param.cashRate;
					rate.limit = param.cashLimit;
					rate.minimum = param.cashMinimum;
					rate.money = param.cashMoney;
					merchantChannelCashRateRepository.save(rate);
				}

			} catch (Exception e) {
				e.printStackTrace();
			}
		}

	}

	public ExecuteResult<?> invokeRegisterChannelDiversity(List<String> ids) {
		ExecutorService threadPool = Executors.newCachedThreadPool();
		FutureTask<Object> future = new FutureTask<>(() -> {
			List<Channel> listChannel = repository.findAllByIdIn(ids);
			for (Channel entity : listChannel) {
				if (StringUtils.isBlank(entity.registerUrl) || entity.company == null) {
					continue;
				}
				registerDiversity(entity);
			}
			return null;
		});
		threadPool.execute(future);
		return ExecuteResult.ok();

	}

	private ExecuteResult<?> registerDiversity(Channel entity) {

		List<Merchant> list = merchantRepository.findAllByCompanyIdIn(entity.company.id);
		for (Merchant item : list) {
			List<MerchantRate> rateList = merchantRateRepository.findAllByMerchantId(item.id);
			List<MerchantCashRate> cashRateList = merchantCashRateRepository.findAllByMerchantId(item.id);
			if (CollectionUtils.isEmpty(rateList) || CollectionUtils.isEmpty(cashRateList)) {
				continue;
			}

			MerchantRateMap param = new MerchantRateMap();
			ObjectUtils.fieldCopy(item, param);
			param.rateList = new ArrayList<>();
			rateList.forEach(i -> {
				RateEntry entry = new RateEntry();
				entry.type = i.type;
				entry.rate = i.rate;
				entry.limit = i.limit;
				entry.minimum = i.minimum;
				entry.money = i.money;
			});

			cashRateList.forEach(i -> {
				param.cashRate = i.rate;
				param.cashMoney = i.money;
				param.cashLimit = i.limit;
				param.cashMinimum = i.minimum;
			});
			try {
				MerchantChannelMap merchantChannel = restTemplate.postForObject(entity.registerUrl, param,
						MerchantChannelMap.class);
				if (merchantChannel == null || StringUtils.isBlank(merchantChannel.key)
						|| StringUtils.isBlank(merchantChannel.no)) {
					continue;
				}
				MerchantChannel merchantChannelResult = merchantChannelRepository.findOneByKeyAndNo(merchantChannel.key,
						merchantChannel.no);
				if (merchantChannelResult != null)
					continue;
				merchantChannelRepository.findAllByMerchantIdAndChannelId(item.id, entity.id)
						.forEach(i -> merchantChannelRepository.delete(i));
				MerchantChannel po = new MerchantChannel();
				ObjectUtils.fieldCopy(merchantChannel, po);
				po.rates = new ArrayList<>();
				po.channel = entity;
				po.addedDate = new Date();
				po.merchant = item;
				po.enabled = true;
				po = merchantChannelRepository.save(po);
				if (CollectionUtils.isNotEmpty(merchantChannel.rateList))
					for (RateEntry i : merchantChannel.rateList) {
						if (i.rate <= 0 || i.type == null)
							continue;
						MerchantChannelRate r = new MerchantChannelRate();
						r.merchantChannel = po;
						r.rate = i.rate;
						r.type = i.type;
						r.limit = i.limit;
						r.minimum = i.minimum;
						r.money = i.money;
						merchantChannelRateRepository.save(r);
					}
				if (String.valueOf(param.cashLimit) != null || String.valueOf(param.cashMinimum) != null
						|| String.valueOf(param.cashMoney) != null || String.valueOf(param.cashRate) != null) {
					MerchantChannelCashRate rate = new MerchantChannelCashRate();
					rate.merchantChannel = po;
					rate.rate = param.cashRate;
					rate.limit = param.cashLimit;
					rate.minimum = param.cashMinimum;
					rate.money = param.cashMoney;
					merchantChannelCashRateRepository.save(rate);
				}

			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return ExecuteResult.ok();
	}

	public List<Channel> findAllHealthEnabled(Boolean enabled) {
		List<Channel> list = repository.findAllByHealthEnabledAndHealthUrlIsNotNull(enabled);
		return list;
	}
}
